/**
 * HEIG-VD
 * MCR - Projet "Pandemie"
 * Auteurs: Thierry Forchelet, Louis Jaquier, Grégory Moinat, Julien Rebetez
 */

package visitable;

import java.util.Collections;
import java.util.HashSet;
import java.util.Observable;
import java.util.Set;

import visitors.Visitor;
import app.IDGenerator;
import app.Identifiable;

/**
 * Une créature qui vit dans notre monde
 */
public abstract class Creature extends Observable implements Visitable, Identifiable {
  public static final int EVENT_DIED = 1;
  public static final int EVENT_VISIT = 2;
  private int id;

  /**
   * On stock les ids des visiteurs qui nous ont visité, on évite ainsi de
   * propager plus d'une fois le meme visiteur a nos voisins, ce qui
   * provoquerait une recursion infinie
   */
  private Set<Integer> seenIDs = Collections.synchronizedSet(new HashSet<Integer>());

  private boolean alive = true;

  public Creature() {
    id = IDGenerator.getInstance().createID();
  }

  // Fait mourir une créature et l'indique aux observateurs
  public void die() {
    alive = false;
    setChanged();
    notifyObservers(EVENT_DIED);
  }

  // Retourne si la créature est vivante
  public boolean isAlive() {
    return alive;
  }

  /**
   * Méthode qui doit être implémentée par les sous-classes qui doit simplement
   * appeler v.visit(this)
   * @param v
   */
  protected abstract void _accept(Visitor v);

  /**
   * Méthode permettant la visite par un visiteur
   */
  @Override
  public boolean accept(final Visitor visitor) {
    if (!seenIDs.contains(visitor.getID())) {
      seenIDs.add(visitor.getID());
      _accept(visitor);
      return true;
    }
    return false;
  }

  /**
   * Effectue une contamination aux voisins de cette creature en utilisant les
   * connexions définies
   */
  public void spread(Visitor v) {
    Set<CreatureConnection> connections = ConnectionManager.getInstance()
        .getConnections(this);
    /*Logger.getInstance().log(this,
        "Propagation à travers " + connections.size() + " connexions");*/
    for (CreatureConnection c : connections)
      SpreadManager.getInstance().addSpread(this, c, v);
  }

  /**
   * Retourne l'id de cette créature
   */
  public int getID() {
    return id;
  }

}
